﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using Caliburn.Micro;
using Scrabble.Model;
using Scrabble.Tasks;

namespace Scrabble.ViewModels
{
    [Export(typeof(GameViewModel)), PartCreationPolicy(CreationPolicy.NonShared)]
    public class GameViewModel : Conductor<PlayerViewModel>.Collection.OneActive, ITimeKeeper
    {
        private readonly Stopwatch _stopwatch = new Stopwatch();
        private readonly IGame _game;
        private readonly BoardViewModel _boardModel;
        private readonly PoolViewModel _tileUsageSummary;
        private readonly LexiconViewModel _wordSearch;

        public event EventHandler StateChanged;

        public GameViewModel(IGame game)
        {
            _game = game;
            _game.TimeKeeper = this;
            _game.ActivePlayerChanged += OnActivePlayerChanged;
            _game.GameOver += OnGameOver;

            _boardModel = new BoardViewModel(_game.Board);
            _tileUsageSummary = new PoolViewModel(_game);
            _wordSearch = IoC.Get<LexiconViewModel>();

            ActivationProcessed += OnActivePlayerModelChanged;

            Items.AddRange(_game.Players.Select(player => new PlayerViewModel(_game, player)));

            if (_game.IsGameOver)
            {
                ActiveItem = Items.First();
            }
            else
            {
                Stopwatch.IsRunning = true;
                ActiveItem = ModelForActivePlayer;
            }
        }

        public Stopwatch Stopwatch
        {
            get { return _stopwatch; }
        }

        public BoardViewModel Board
        {
            get { return _boardModel; }
        }

        public object TileUsageSummary
        {
            get { return _tileUsageSummary; }
        }

        public object WordSearch
        {
            get { return _wordSearch; }
        }

        public IList<string> NamesOfPlayers
        {
            get { return Items.Select(item => item.Player.Name).ToList(); }
        }

        public void Pass()
        {
            _game.ActivePlayer.Pass();
        }

        public IResult Save(string fileName)
        {
            return new SerializationTask<StateOfPlay>
            {
                FileName = fileName,
                Source = _game.StateOfPlay
            };
        }

        private PlayerViewModel ModelForActivePlayer
        {
            get { return Items.FirstOrDefault(item => item.Player == _game.ActivePlayer); }
        }

        private void OnGameOver(object sender, EventArgs e)
        {
            Stopwatch.IsRunning = false;
            Stopwatch.Reset();
            NotifyOfStateChanged();
        }

        private void OnActivePlayerModelChanged(object sender, ActivationProcessedEventArgs e)
        {
            _boardModel.InputBox = ActiveItem == null ? null : ActiveItem.InputBox;
            NotifyOfStateChanged();
        }

        private void OnActivePlayerChanged(object sender, EventArgs e)
        {
            Stopwatch.Reset();
            if (_game.ActivePlayer != null) ActivateItem(ModelForActivePlayer);
        }

        private void NotifyOfStateChanged()
        {
            var handler = StateChanged;
            if (handler != null) handler(this, EventArgs.Empty);
        }

        TimeSpan ITimeKeeper.TimeInPlay
        {
            get { return Stopwatch.TotalRunningTime; }
        }
    }
}
